#include "mod.h"
#include <stdint.h>
#include <string.h>
#define BOOL int

void float_to_modbus_registers(float f_val, uint16_t *high_word, uint16_t *low_word);
uint16_t high = 0;
uint16_t low = 0;
void *control_handler(void *arg)
{
    // struct recvmsg rev;
    struct message dev;
    modbus_t *ctx=(modbus_t*)arg;
        while(1)
        {
           msg_queue_recv("modbus",&dev,sizeof(dev),100,0);
            switch (dev.key)
            {
            case 101:
                break;
            case 102:
                break;
                case 103:
                modbus_write_bit(ctx,0,dev.val.b_val);
                break;
                case 104:
                float_to_modbus_registers(dev.val.f_val,&high,&low);
                modbus_write_register(ctx,0,high);
                modbus_write_register(ctx,1,low);
                break;
                case 105:
                modbus_write_bit(ctx,1,dev.val.b_val);
                break;
                case 106:
                modbus_write_register(ctx,2,dev.val.f_val);
                break;
                case 107:
                modbus_write_bit(ctx,2,dev.val.b_val);
                break;
                case 108:
                modbus_write_register(ctx,4,dev.val.f_val);
                break;
            default:
                break;   
            }
        }
}
modbus_t *ctx;
int main(int argc, char const *argv[])
{
    // 创建modbus实例
    uint16_t dest_inputregister[4]; // 输入寄存器
    uint16_t dest_register[6];      // 保持寄存器
    uint8_t dest[3];                // 线圈
    float tem;                      // 温度
    float hum;                      // 湿度
    float air_temp;    //室内温度
    float light_data;  // 灯光强度
    float oxygen_data; // 血氧浓度
    ctx = modbus_new_tcp(argv[1], 502); //创建modbus实例
    if (ctx == NULL)
    {
        printf("modbus new tcp err\n");
        return -1;
    }
    // 设置从机ID
    modbus_set_slave(ctx, 1);
    // 建立连接
    if (modbus_connect(ctx) < 0)
    {
        printf("modbus connect err\n");
        modbus_free(ctx);
        return -1;
    }
    printf("connect ok\n");

    // 共享内存

    struct shm_param shm;
    shm_init(&shm, "haha", 1024);
    int *p = shm_getaddr(&shm);
    int num = *p;
    struct data *q = (struct data *)(p+2);
    q+=num;
    // 线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, control_handler, ctx) != 0)
    {
        perror("create err");
        modbus_free(ctx);
        modbus_close(ctx);
        return -1;
    } 
    while (1)
    {
        // 读输入寄存器数值
        // slave端设置数据格式为float ABCD格式，原因modbus数据域是按照大端方式存储的
        // ，虚拟机默认是小端存储，为了保证数据无误，读取时用dcba的函数
        modbus_read_input_registers(ctx, 0, 2, dest_inputregister);
        tem = modbus_get_float_dcba(dest_inputregister);
        q->val.f_val = tem;
        printf("%.2f\n", q->val.f_val);
        q++;

        modbus_read_input_registers(ctx, 2, 2, dest_inputregister);
        hum = modbus_get_float_dcba(dest_inputregister);
        q->val.f_val = hum;
        printf("%.2f\n", q->val.f_val);
        q++;

        modbus_read_bits(ctx, 0, 3, dest);
        q->val.i_val = dest[0];
        q++;
        // 读保持寄存器
        modbus_read_registers(ctx, 0, 2, dest_register);
        air_temp = modbus_get_float_dcba(dest_register);
        q->val.f_val = air_temp;
        printf("%.2f\n", q->val.f_val);
        q++;

        q->val.i_val = dest[1];
        q++;

        modbus_read_registers(ctx, 2, 2, dest_register);
        light_data = modbus_get_float_dcba(dest_register);
        q->val.f_val = light_data;
        printf("%.2f\n", q->val.f_val);
        q++;

        q->val.i_val = dest[2];
        q++;

        modbus_read_registers(ctx, 4, 2, dest_register);
        oxygen_data = modbus_get_float_dcba(dest_register);
        q->val.f_val = oxygen_data;
        printf("%.2f\n", q->val.f_val);
        q++;
        q = (struct data *)(p+2);//重置指针位置
        q+=num;
        sleep(3);
    }
    // 释放
    pthread_join(tid,NULL);
    modbus_free(ctx);
    modbus_close(ctx);
    return 0;
}

// 函数：将浮动值转换为两个 16 位寄存器
void float_to_modbus_registers(float f_val, uint16_t *high_word, uint16_t *low_word) 
{
    // 1. 获取浮点数的 32 位整数表示
    uint32_t int_value;
    memcpy(&int_value, &f_val, sizeof(f_val));  // 将浮动数拷贝到 32 位整数
    // 2. 将 32 位整数分解为两个 16 位寄存器
    *high_word = (int_value >> 16) & 0xFFFF;  // 获取高 16 位
    *low_word = int_value & 0xFFFF;           // 获取低 16 位
}

